import requests
import os
import sys
from typing import Optional
from concurrent.futures import ThreadPoolExecutor
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if project_root not in sys.path:
    sys.path.append(project_root)

from settings import BILIBILI_HEADERS
from components.utils import extract_bv_and_p_from_url, get_video_info, get_video_cid_aid

def make_video_audio_path(fp):
    video_path = fp
    audio_path = f"{fp[:-4]}.mp3"
    return video_path, audio_path

def download_file(url: str, filepath: str, headers: Optional[dict] = None) -> bool:
    try:
        response = requests.get(url, headers=headers or BILIBILI_HEADERS, stream=True)
        response.raise_for_status()
        os.makedirs(os.path.dirname(filepath), exist_ok=True)
        with open(filepath, 'wb') as f:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    f.write(chunk)
        return True
    except Exception as e:
        print(f"下载失败: {str(e)}")
        return False

def download_bili(bv_number, p_number, fp):
    try:
        video_path, audio_path = make_video_audio_path(fp)
        if os.path.exists(video_path) and os.path.exists(audio_path):
            return video_path, audio_path
        info = get_bili_download_urls(bv_number, p_number)
        if not info['video'] or not info['audio']:
            raise Exception("无法获取视频或音频链接")
        # 选择最高质量的视频和音频
        video_url = info['video'][0]['url']
        audio_url = info['audio'][0]['url']

        with ThreadPoolExecutor(max_workers=2) as executor:
            print("开始下载视频和音频...")
            video_future = executor.submit(download_file, video_url, video_path)
            audio_future = executor.submit(download_file, audio_url, audio_path)
            video_success = video_future.result()
            audio_success = audio_future.result()
        if not video_success or not audio_success:
            raise Exception("视频或音频下载失败")
        return video_path, audio_path
    except Exception as e:
        print("发生错误:", str(e))
        return False

def get_bili_download_urls(bv_number, p_number) -> dict:
    try:
        meta_data = get_video_info(bv_number)
        cid, aid = get_video_cid_aid(meta_data, p_number)
        play_url = f"https://api.bilibili.com/x/player/playurl?avid={aid}&cid={cid}&qn=112&fnval=4048"
        response = requests.get(play_url, headers=BILIBILI_HEADERS)
        response.raise_for_status()
        data = response.json()
        
        if data['code'] != 0:
            raise Exception(f"获取下载链接失败: {data['message']}")
        result = {
            'title': meta_data['title'],
            'cover': meta_data['pic'],
            'owner': meta_data['owner']['name'],
            'video': [],
            'audio': []
        }
        # 获取视频流
        if 'data' in data and 'dash' in data['data']:
            # 视频流
            for video in data['data']['dash']['video']:
                result['video'].append({
                    'quality': video['id'],
                    'url': video['baseUrl']
                })
            # 音频流
            for audio in data['data']['dash']['audio']:
                result['audio'].append({
                    'quality': audio['id'],
                    'url': audio['baseUrl']
                })
        return result
    except Exception as e:
        raise Exception(f"获取下载链接失败: {str(e)}")


def download_video(url, fp="tmp"):
    if url.startswith("https://www.bilibili.com/video/"):
        bv_number, p_number = extract_bv_and_p_from_url(url)
        return download_bili(bv_number, p_number, fp)
    else:
        raise Exception("无效的URL")


if __name__ == '__main__':
    # 测试视频下载
    test_url = "https://www.bilibili.com/video/BV1wy4y1D7JT/?p=3"
    download_video(test_url)